
import 'package:camera/camera.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'dart:async';

abstract class CameraState<T extends StatefulWidget> extends State<T> with WidgetsBindingObserver {

  CameraController? controller;
  List<CameraDescription>? _cameras;
  FlashMode flashMode = FlashMode.off;

  double _minAvailableExposureOffset = 0.0;
  double _maxAvailableExposureOffset = 0.0;
  double _currentExposureOffset = 0.0;
  double _currentBrightnessOffset = 1;
  // Counting pointers (number of user fingers on screen)
  int _pointers = 0;
  double _minAvailableZoom = 1.0;
  double _maxAvailableZoom = 1.0;
  double _currentScale = 1.0;
  double _baseScale = 1.0;
  bool _flashOpacity = false;

  GlobalKey<FocusViewState>? _focusKey;

  ///当前亮度
  double get currentBrightness => _currentBrightnessOffset;
  ///最小可用曝光度
  double get minAvailableExposure => _minAvailableExposureOffset;
  ///最大可用曝光度
  double get maxAvailableExposure => _maxAvailableExposureOffset;
  ///当前的曝光度
  double get currentExposure => _currentExposureOffset;
  ///相机是否已初始化
  bool get isCameraReady => controller != null && controller!.value.isInitialized;
  ///当前是否在拍照
  bool get isTakingPicture => controller != null && controller!.value.isTakingPicture;
  ///当前是否在录像
  bool get isRecordingVideo => controller != null && controller!.value.isRecordingVideo;

  bool get openAudio => false;
  ///是否自动聚焦
  bool get autoFocus => false;

  Resolution? _resolution;
  Resolution get resolution => _resolution??Resolution.high;

  ImageRatio? _ImageRatio;
  ImageRatio get imageRatio => _ImageRatio??ImageRatio.ratio_4_3;
  List<CameraDescription>? get cameras => _cameras;

  Timer? _autoFocusTimer;
  Offset? _lastFocusPoint;

  @override
  void initState() {
    super.initState();
    _focusKey = GlobalKey();
    WidgetsBinding.instance.addObserver(this);

    startAutoFocus();
  }

  initCamera({Resolution? resolution, ImageRatio? ratio}) async {
    if(resolution == null && ratio == null) {
      resolution = Resolution.high;
    }
    _cameras = await availableCameras();
    if (_cameras == null) return;
    _resolution = resolution;
    _ImageRatio = ratio;
    onCameraChange(_cameras!.first, resolute: _resolution, ratio: _ImageRatio);
  }

  ///如果要支持后台录像，则子类的该方法置为空
  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    log(state);

    if (state == AppLifecycleState.inactive) {
      controller?.dispose();
      controller = null;
    } else if (state == AppLifecycleState.resumed) {
      // _onCameraChange(controller!.description);
      if (_cameras == null) return;
      //在鸿蒙手机上，首次申请权限的时候 会黑屏，所以需要加个延时
      Future.delayed(Duration(milliseconds: 200)).then((value) {
        onCameraChange(_cameras!.first, resolute: _resolution, ratio: _ImageRatio);
      });
    }
  }

  @override
  void dispose() {
    setBrightnessOffset(0.5, false);
    controller?.dispose();
    controller = null;
    WidgetsBinding.instance.removeObserver(this);
    _autoFocusTimer?.cancel();
    super.dispose();
  }

  void takePictureFlash() {
    // 显示闪光效果
    setState(() {
      _flashOpacity = true;
    });

    // 延时恢复正常显示
    Future.delayed(const Duration(milliseconds: 100), () {
      setState(() {
        _flashOpacity = false;
      });
    });
  }

  ///相机预览界面
  Widget cameraPreviewWidget() {
    final CameraController? cameraController = controller;
    if (cameraController == null || !cameraController.value.isInitialized) {
      return Container();
    }
    if(_flashOpacity) {
      // 假装闪光效果
      return Container(color: Colors.black);
    }

    Widget w = Listener(
      onPointerDown: (_) => _pointers++,
      onPointerUp: (_) => _pointers--,
      child: CameraPreview(
        controller!,
        focusKey: _focusKey,
        child: LayoutBuilder(
            builder: (BuildContext context, BoxConstraints constraints) {
              return GestureDetector(
                behavior: HitTestBehavior.opaque,
                onScaleStart: _handleScaleStart,
                onScaleUpdate: _handleScaleUpdate,
                onDoubleTap: handleDoubleTap,
                onTapDown: (TapDownDetails details) => _onViewFinderTap(details, constraints),
              );
            }),
      ),
    );
    return w;
  }

  void handleDoubleTap() {}

  void _handleScaleStart(ScaleStartDetails details) {
    _baseScale = _currentScale;
  }

  Future<void> _handleScaleUpdate(ScaleUpdateDetails details) async {
    // When there are not exactly two fingers on screen don't scale
    if (controller == null || _pointers != 2) {
      return;
    }

    _currentScale = (_baseScale * details.scale).clamp(_minAvailableZoom, _maxAvailableZoom);
    await controller!.setZoomLevel(_currentScale);
  }

  void _onViewFinderTap(TapDownDetails details, BoxConstraints constraints) {
    if (controller == null) {
      return;
    }

    final CameraController cameraController = controller!;

    double clickX = details.localPosition.dx;
    double clickY = details.localPosition.dy;
    final Offset offset = Offset(
      clickX/ constraints.maxWidth,
      clickY/ constraints.maxHeight,
    );
    _focusKey?.currentState?.handleTapDown(clickX, clickY);
    cameraController.setExposurePoint(offset);
    cameraController.setFocusPoint(offset);
    mountedState();
  }

  ///聚焦
  void focusPoint(Offset offset){
    if (controller == null) {
      return;
    }
    final CameraController cameraController = controller!;
    cameraController.setExposurePoint(offset);
    cameraController.setFocusPoint(offset);
  }

  ///自动聚焦的间隔
  int get autofocusPeriodic => 5000;
  ///手动聚焦后，取消自动聚焦，之后15秒再次触发自动聚焦
  int get focusAfterCancel => 15000;

  ///移除自动聚焦，15秒后再次触发自动聚焦
  void _cancelFocus(){
    if(!autoFocus) return;
    _autoFocusTimer?.cancel();
    _autoFocusTimer = Timer(Duration(milliseconds: focusAfterCancel), startAutoFocus);
  }

  ///自动聚焦，每秒聚焦一次，聚焦点默认中心，否则为上次手动聚焦点
  void startAutoFocus(){
    if(!autoFocus) return;
    _autoFocusTimer?.cancel();
    _autoFocusTimer = Timer.periodic(Duration(milliseconds: autofocusPeriodic), (timer) {
      focusPoint(_lastFocusPoint ?? const Offset(0.5, 0.5));
    });
  }

  ///切换摄像头
  void switchCamera() {
    if(controller == null || _cameras == null) return;
    if (controller!.description == _cameras!.first) {
      onCameraChange(_cameras![1]); //部分手机cameras有多个，所以用下标来选择
    } else {
      flashMode = FlashMode.off;
      onCameraChange(_cameras![0]);
    }
  }

  void onCameraChange(CameraDescription cameraDescription, {Resolution? resolute, ImageRatio? ratio}) async {
    if (controller != null && resolute == null && ratio == null) {
      controller!.setDescription(cameraDescription);
      return;
    }

    final CameraController cameraController = CameraController(
      cameraDescription,
      resolution: resolute?.value,
      ratio: ratio,
      imageFormatGroup: ImageFormatGroup.jpeg,
      enableAudio: openAudio,
    );

    controller = cameraController;

    // If the controller is updated then update the UI.
    cameraController.addListener(() {
      mountedState();
      if (cameraController.value.hasError) {
        log('Camera error ${cameraController.value.errorDescription}');
      }
    });

    try {
      await cameraController.initialize(overlayWidth: overlayWidth, overlayStyle: overlayStyle);
      if(!kIsWeb && controller != null) {
        // The exposure mode is currently not supported on the web.
        await Future.wait(<Future<Object?>>[
          controller!.getMinExposureOffset().then((v) => _minAvailableExposureOffset = v),
          controller!.getMaxExposureOffset().then((v) => _maxAvailableExposureOffset = v),
          controller!.getMaxZoomLevel().then((v) => _maxAvailableZoom = v),
          controller!.getMinZoomLevel().then((v) => _minAvailableZoom = v),
        ]);
      }
      //初始化还原曝光度
      setExposureOffset(0);
      setFocusMode();
    } catch (e) {
      log(e);
    }
    mountedState();
  }

  int get overlayWidth => 0;
  OverlayStyle get overlayStyle => OverlayStyle.NoOverlay;

  ///聚焦模式：插件默认自动聚焦，这里设置默认手动聚焦
  Future setFocusMode({FocusMode mode = FocusMode.locked}) async {
    if (!isCameraReady) {
      return;
    }
    try {
      await controller!.setFocusMode(mode);
    } on CameraException catch (e) {
      log(e);
      rethrow;
    }
  }

  ///闪光灯
  Future setFlashMode(FlashMode mode) async {
    if (!isCameraReady) {
      return;
    }
    try {
      await controller!.setFlashMode(mode);
    } on CameraException catch (e) {
      log(e);
      rethrow;
    }
  }

  Future<void> setExposureMode(ExposureMode mode) async {
    if (!isCameraReady) {
      return;
    }

    try {
      await controller!.setExposureMode(mode);
    } on CameraException catch (e) {
      log(e);
      rethrow;
    }
  }

  ///设置曝光度
  void setExposureOffset(double offset) async {
    if (!isCameraReady || controller!.isDisposed) {
      return;
    }

    if (mounted) {
      setState(() {
        _currentExposureOffset = offset;
      });
    }
    try {
      offset = await controller!.setExposureOffset(offset);
      // return offset;
    } on CameraException catch (e) {
      log(e);
      rethrow;
    }
  }

  ///设置亮度
  Future<double> setBrightnessOffset(double offset, [bool refreshUI = true]) async {
    if (!isCameraReady || controller!.isDisposed) {
      return 0;
    }
    if (refreshUI) {
      mountedState(() {
        _currentBrightnessOffset = offset;
      });
    }
    try {
      offset = await controller!.setBrightness(offset);
      return offset;
    } on CameraException catch (e) {
      log(e);
      rethrow;
    }
  }

  /// 录像清晰度选择
  bool setResolutionPreset(Resolution res) {
    if(controller == null || _cameras == null) return false;
    _resolution = res;
    if (controller!.description == _cameras!.first) {
      onCameraChange(_cameras![0], resolute: _resolution); //部分手机cameras有多个，所以用下标来选择
    } else {
      onCameraChange(_cameras![1], resolute: _resolution);
    }
    return true;
  }


  /// 图片比例选择
  bool setImageRatio(ImageRatio res) {
    if(controller == null || _cameras == null) return false;
    _ImageRatio = res;
    if (controller!.description == _cameras!.first) {
      onCameraChange(_cameras![0], ratio: _ImageRatio); //部分手机cameras有多个，所以用下标来选择
    } else {
      onCameraChange(_cameras![1], ratio: _ImageRatio);
    }
    return true;
  }

  ///是否是背后的摄像头
  bool get isBackCamera => controller?.description == _cameras?.first;

  log(string) => print("CameraState: $string");

  void mountedState([VoidCallback? fn]) {
    if(mounted) setState(fn ?? (){});
  }
}